//
//  NSObject+EC.m
//  ECDevelopKit
//
//  Created by LittoCats on 8/6/14.
//  Copyright (c) 2014 Littocats. All rights reserved.
//

#import "NSObject+ECS.h"

#import <CommonCrypto/CommonDigest.h>
#import <objc/runtime.h>
#import <objc/message.h>


@implementation NSObject (EC)

static const char *kECSNSObjectIdKey;
@dynamic _id;
- (NSString *)_id
{
    NSString *_id = objc_getAssociatedObject(self, &kECSNSObjectIdKey);
    if (!_id) {
        _id = [[NSString alloc] initWithFormat:@"%@_%p",NSStringFromClass(self.class), self];
        [self set_id:_id];
        [[NSObject objectMapTable] setObject:self forKey:_id];
    }
    return _id;
}
- (void)set_id:(NSString *)_id
{
    objc_setAssociatedObject(self, &kECSNSObjectIdKey, _id, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

#pragma mark- findObjectById
+ (id)findObjectById:(NSString *)_id
{
    return [[self objectMapTable] objectForKey:_id];
}

#pragma mark- 单例，记录 NSObjectId 与 NSObject 的对应关系
+ (NSMapTable *)objectMapTable
{
    static NSMapTable *mapTable = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        mapTable = [[NSMapTable alloc] initWithKeyOptions:NSPointerFunctionsStrongMemory valueOptions:NSPointerFunctionsWeakMemory capacity:128];
    });
    return mapTable;
}

#pragma mark- isEmpty
- (BOOL)isEmpty
{
    return self == [NSNull null];
}

#pragma mark-

@end

@implementation NSString (EC)

//长度为零时，为空
- (BOOL)isEmpty
{
    return [super isEmpty] || self.length == 0;
}

//MD5
@dynamic MD5;
static const char *kECNSStringMD5Key;
- (NSString *)MD5
{
    NSString *MD5 = objc_getAssociatedObject(self, &kECNSStringMD5Key);
    if ([self isMemberOfClass:[NSString class]] && MD5) {
        return MD5;
    }
    CC_MD5_CTX md5;
	CC_MD5_Init (&md5);
	CC_MD5_Update (&md5, [self UTF8String], (CC_LONG)[self length]);
    
	unsigned char digest[CC_MD5_DIGEST_LENGTH];
	CC_MD5_Final (digest, &md5);
	MD5 = [[NSString alloc] initWithFormat: @"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
           digest[0],  digest[1],
           digest[2],  digest[3],
           digest[4],  digest[5],
           digest[6],  digest[7],
           digest[8],  digest[9],
           digest[10], digest[11],
           digest[12], digest[13],
           digest[14], digest[15]];
    if ([self isMemberOfClass:[NSString class]]) objc_setAssociatedObject(self, &kECNSStringMD5Key, MD5, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
	return MD5;
}

@dynamic base64;
- (NSString *)base64
{
    return [[self dataUsingEncoding:NSUTF8StringEncoding] base64];
}

@dynamic base64DecodeData;
- (NSData *)base64DecodeData
{
    if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0) {
        return [[NSData alloc] initWithBase64EncodedString:self options:NSDataBase64DecodingIgnoreUnknownCharacters];
    }else{
        return [[NSData alloc] initWithBase64Encoding:self];
    }
}

@dynamic base64DecodeString;
- (NSString *)base64DecodeString
{
    return [[NSString alloc] initWithData:[self base64DecodeData] encoding:NSUTF8StringEncoding];
}
@end

@implementation NSDictionary (EC)

//无素个数为零时，为空
- (BOOL)isEmpty
{
    return [super isEmpty] || !self.count;
}

@end

@implementation NSArray (EC)

//无素个数为零时，为空
- (BOOL)isEmpty
{
    return [super isEmpty] || !self.count;
}

@end

@implementation NSData (EC)

@dynamic MD5;
static const char *kECNSDataMD5Key;
- (NSString *)MD5
{
    NSString *MD5 = objc_getAssociatedObject(self, &kECNSDataMD5Key);
    if ([self isMemberOfClass:[NSData class]] && MD5) {
        return MD5;
    }
    CC_MD5_CTX md5;
	CC_MD5_Init (&md5);
	CC_MD5_Update (&md5, [self bytes], (CC_LONG)[self length]);
    
	unsigned char digest[CC_MD5_DIGEST_LENGTH];
	CC_MD5_Final (digest, &md5);
	MD5 = [[NSString alloc] initWithFormat: @"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
				   digest[0],  digest[1],
				   digest[2],  digest[3],
				   digest[4],  digest[5],
				   digest[6],  digest[7],
				   digest[8],  digest[9],
				   digest[10], digest[11],
				   digest[12], digest[13],
				   digest[14], digest[15]];
    if ([self isMemberOfClass:[NSData class]]) objc_setAssociatedObject(self, &kECNSDataMD5Key, MD5, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
	return MD5;
}

@dynamic base64;
- (NSString *)base64
{
    if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0) {
        return [self base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
    }else{
        return [self base64Encoding];
    }
}
@end